package cn.swust.designpatternlearningplatform.Interceptor;


import cn.swust.designpatternlearningplatform.common.AnnotationUtils.Authentication;
import cn.swust.designpatternlearningplatform.common.AnnotationUtils.NotNull;
import cn.swust.designpatternlearningplatform.common.Result.R;
import com.alibaba.fastjson.JSON;
import cn.swust.designpatternlearningplatform.common.exception.AuthenticationException;
import cn.swust.designpatternlearningplatform.common.utils.AuthUserContext;
import cn.swust.designpatternlearningplatform.common.utils.JwtUtils;
import cn.swust.designpatternlearningplatform.domain.bo.TokenInfoBo;
import cn.swust.designpatternlearningplatform.domain.enums.RoleEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
        response.setCharacterEncoding("UTF-8");
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            token = request.getParameter("token");
        }
        log.info(token);
        // 验证token
        if (!JwtUtils.verifyToken(token)) {
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(JSON.toJSONString(R.error("登录信息过期")));
            return false;
        }
        // 获取身份
        TokenInfoBo tokenInfoBo = JwtUtils.parseToken(token);
        log.info("tokenInfoBo : {} ", tokenInfoBo);
        // 将身份信息放入上下文对象中
        AuthUserContext.set(tokenInfoBo);

        // 在访问的方法上寻找注解
        if (handler instanceof HandlerMethod) {

            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Authentication permission = handlerMethod.getMethodAnnotation(Authentication.class);
            // 若为null则在访问的方法所属的类上寻找注解
            if (permission == null) {
                permission = ((HandlerMethod) handler).getBeanType().getAnnotation(Authentication.class);
            }
            // 若上述的都为空，则直接放行
            if (permission == null) {
                return true;
            }
            // 进行角色权限校验
            String realRole = tokenInfoBo.getRole();
            RoleEnum[] roles = permission.value();
            // 都没问题则放行
            return checkRole(realRole, roles, response);
        }
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(JSON.toJSONString(R.error("未找到该功能")));
        return false;
    }

    /**
     * 进行权限校验
     */
    private boolean checkRole(String realRole, RoleEnum[] roles, HttpServletResponse response) throws IOException {
        for (RoleEnum role : roles) {
            if (role.getRoleName().equals(realRole)) {
                return true;
            }
        }
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(JSON.toJSONString(R.error("暂无权限")));
        return false;
    }

    @Override
    public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) throws Exception {
        // 方法调用结束后clear，防止内存泄露
        AuthUserContext.clear();
    }
}
